package com.blandware.atleap.webapp.filter;

import com.blandware.atleap.common.Constants;
import com.blandware.atleap.common.util.StringUtil;
import com.blandware.atleap.model.core.User;
import com.blandware.atleap.service.core.UserManager;
import com.blandware.atleap.webapp.util.core.RequestUtil;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.context.SecurityContextImpl;
import org.acegisecurity.providers.dao.UserCache;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * <p>Intercepts Login requests for "Remember Me" functionality.</p>
 * <p><a href="LoginFilter.java.html"><i>View Source</i></a>
 * </p>
 *
 * @author Matt Raible <a href="mailto:matt@raibledesigns.com">&lt;matt@raibledesigns.com&gt;</a>
 * @version $Revision: 1.13 $ $Date: 2006/03/09 16:46:05 $
 * @web.filter name="loginFilter"
 * @web.filter-init-param name="enabled" value="${rememberMe.enabled}"
 */
public final class LoginFilter implements Filter {
	//~ Instance fields ========================================================

	protected transient final Log log = LogFactory.getLog(LoginFilter.class);
	protected FilterConfig config = null;
	protected boolean enabled = true;

	//~ Methods ================================================================

    /**
     * Filters a request
     *
     * @param req   Filtered request
     * @param resp  Response that will be result of filtering
     * @param chain Chain of following filters
     * @throws IOException
     * @throws ServletException
     */
	public void doFilter(ServletRequest req, ServletResponse resp,
	                     FilterChain chain)
	        throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
        String username = request.getRemoteUser();

        // See if the user has a remember me cookie
		Cookie c = RequestUtil.getCookie(request, Constants.LOGIN_COOKIE);

		WebApplicationContext context =
		        (WebApplicationContext) config.getServletContext().getAttribute
		        (WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		UserManager mgr = (UserManager) context.getBean(Constants.USER_MANAGER_BEAN);

		// Check to see if the user is logging out, if so, remove all
		// login cookies
		if ( request.getRequestURL().indexOf("logout") != -1 &&
		        username != null ) {
			// make sure user's session hasn't timed out
			if ( username != null ) {
				if ( log.isDebugEnabled() ) {
					log.debug("logging out '" + request.getRemoteUser() + "'");
				}
				mgr.deleteUserCookies(username);
				RequestUtil.deleteCookie(response, c, request.getContextPath());

                //logout
                UserCache userCache = (UserCache) context.getBean(Constants.ACEGI_USER_CACHE_BEAN);
                if (userCache != null)
                    userCache.removeUserFromCache(username);

                SecurityContextHolder.setContext(new SecurityContextImpl());
				request.getSession().invalidate();
			}
		} else if ( c != null && enabled ) {
			try {

				String loginCookie = mgr.checkUserCookie(c.getValue());

				if ( loginCookie != null ) {
					RequestUtil.setCookie(response, Constants.LOGIN_COOKIE,
					        loginCookie,
					        request.getContextPath());
					loginCookie = StringUtil.decodeString(loginCookie);

					String[] value = StringUtils.split(loginCookie, '|');

					User user = mgr.retrieveUser(value[0]);

					// authenticate user without displaying login page
					String route = "/servlet/authorize?j_username=" +
					        user.getName() + "&j_password=" +
					        user.getPassword();

					request.setAttribute("encrypt", "false");
					request.getSession(true).setAttribute("cookieLogin",
					        "true");

					if ( log.isDebugEnabled() ) {
						log.debug("I remember you '" + user.getName() +
						        "', attempting to authenticate...");
					}

					RequestDispatcher dispatcher =
					        request.getRequestDispatcher(route);
					dispatcher.forward(request, response);

					return;
				}
			} catch ( Exception e ) {
				if ( log.isDebugEnabled() ) {
					log.error(e);
				}
				throw new ServletException(e);
			}
		}

		chain.doFilter(req, resp);
	}

	/**
	 * Initializes controller values of filter.
	 */
	public void init(FilterConfig config) {
		this.config = config;

		String param = config.getInitParameter("enabled");
		enabled = Boolean.valueOf(param).booleanValue();

		if ( log.isDebugEnabled() ) {
			log.debug("Remember Me enabled: " + enabled);
		}

		config.getServletContext()
		        .setAttribute("rememberMeEnabled",
		                config.getInitParameter("enabled"));
	}

	/**
	 * Destroys any instance values other than config *
	 */
	public void destroy() {
	}
}
